package org.jianfa.learn.dubbo.filter;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class DataDistribution {

    //方法名称
    private String methodName;
    //环形数组
    private DataBuffer[] dataBuffers;
    //当前窗口
    private Integer index;
    //锁
    private Object lock;

    //初始化DataDistribution
    public DataDistribution(String methodName) {
        this.methodName = methodName;
        dataBuffers = new DataBuffer[60/5];
        for (int i=0; i<(60/5); i++) {
            dataBuffers[i] = new DataBuffer();
        }
        index = 0;
        lock = new Object();
        //0~5秒开始收集
        synchronized (lock) {
            dataBuffers[index].startCollection();
        }
    }

    //在当前的dataBuffer里面记录该次的响应时间responseTime
    public void recoredResponseTime(double responseTime) {
        synchronized (lock) {
            Integer currentIndex = index;
            DataBuffer dataBuffer = dataBuffers[currentIndex];
            dataBuffer.recoredResponseTime(responseTime);
        }
    }

    //由这个方法来升级index
    //升级index和清空dataBuffer必须是一个原子操作
    //0s 5s 10s 15s ....
    public void report() {
        List<Double> responseTimeFromLastMinute = new LinkedList<>();
        int previousIndex = index;
        DataBuffer previousBuffer = dataBuffers[previousIndex];
        List<Double> nextBuf = new LinkedList<>();
        synchronized (lock) {
            //计算出下一次用来收集响应时间的index
            index = (index + 1) % dataBuffers.length;

            //上一个DataBuffer停止收集
            previousBuffer.endCollection();

            DataBuffer nextDataBuffer = dataBuffers[index];
            nextBuf = nextDataBuffer.getBuf();

            //下一个DataBuffer开始收集
            nextDataBuffer.startCollection();
        }

        int changeRangeStart = 0;
        int changeRangeEnd = 0;
        int unchange = 0;
        for (int i=0; i<dataBuffers.length; i++) {
            //跳过当前的index
            if (index == i) {
                responseTimeFromLastMinute.addAll(nextBuf);
                unchange = unchange + nextBuf.size();
            } else {
                DataBuffer dataBuffer = dataBuffers[i];
                List<Double> buf = dataBuffer.getBuf();
                responseTimeFromLastMinute.addAll(buf);
                if (i == previousIndex) {
                    changeRangeStart = unchange;
                    changeRangeEnd = unchange + buf.size();
                } else {
                    unchange = unchange + buf.size();
                }
            }
        }

        //System.out.printf("previousIndex:%d Index:%d 排序前响应时间一览：%n",
        //        previousIndex, index, changeRangeStart, changeRangeEnd);
        //for (int i=0; i<responseTimeFromLastMinute.size(); i++) {
        //    if (i>0 && i%10 == 0) {
        //        System.out.printf("%n");
        //    }
        //    if (i >= changeRangeStart && i <= changeRangeEnd) {
        //        System.out.printf("%8.2f*", responseTimeFromLastMinute.get(i));
        //    } else {
        //        System.out.printf("%8.2f", responseTimeFromLastMinute.get(i));
        //    }
        //}
        //System.out.printf("%n");

        //排序
        Collections.sort(responseTimeFromLastMinute);

        //计算tp90
        int tp90Index = (int)(0.9 * responseTimeFromLastMinute.size() - 1);
        Double tp90 = responseTimeFromLastMinute.get(tp90Index);

        //计算tp99
        int tp99Index = (int)(0.99 * responseTimeFromLastMinute.size() - 1);
        Double tp99 = responseTimeFromLastMinute.get(tp99Index);

        String startTime = previousBuffer.getStartTime();
        String endTime = previousBuffer.getEndTime();

        //打印日志
        System.out.printf("方法%s [%s 到 %s] TP90是%.2f毫秒 TP99是%.2f毫秒%n", methodName, startTime, endTime, tp90, tp99);
        //System.out.printf("previousIndex:%d Index:%d 排序后响应时间一览：%n", previousIndex, index);
        //for (int i=0; i<responseTimeFromLastMinute.size(); i++) {
        //    if (i>0 && i%10 == 0) {
        //        System.out.printf("%n");
        //    }
        //    System.out.printf("%8.2f", responseTimeFromLastMinute.get(i));
        //}
        //System.out.printf("%n");
    }
}
